package io.hellsinger.filesystem.linux.attribute

import io.hellsinger.filesystem.checkScheme
import io.hellsinger.filesystem.linux.LinuxFileOperationProvider
import io.hellsinger.filesystem.linux.LinuxOperationOptions
import io.hellsinger.filesystem.linux.LinuxOperationOptions.Status.System.NO_DEVICE_FILES
import io.hellsinger.filesystem.linux.LinuxOperationOptions.Status.System.NO_EXECUTION
import io.hellsinger.filesystem.linux.LinuxOperationOptions.Status.System.NO_UPDATE_ACCESS_TIME
import io.hellsinger.filesystem.linux.LinuxOperationOptions.Status.System.NO_UPDATE_DIRECTORY_ACCESS_TIME
import io.hellsinger.filesystem.linux.LinuxOperationOptions.Status.System.READ_ONLY
import io.hellsinger.filesystem.path.Path

interface LinuxFileSystemInfo {
    val id: Long

    val totalSpace: Long

    val usedSpace: Long

    val freeSpace: Long

    val availableSpace: Long

    val maxNameLength: Long

    val hasAccessToDevices: Boolean

    val hasAccessToExecute: Boolean

    val updatesAccessTime: Boolean

    val updatesDirectoryAccessTime: Boolean

    val isReadOnly: Boolean
}

internal class LinuxFileSystemAttributeImpl(
    val blockSize: Long,
    val fragmentSize: Long,
    val blockCount: Long,
    val freeBlockCount: Long,
    val availableBlockCount: Long,
    val fileCount: Long,
    val freeFileCount: Long,
    val availableFileCount: Long,
    override val id: Long,
    val flags: Long,
    override val maxNameLength: Long,
) : LinuxFileSystemInfo {
    override val totalSpace: Long
        get() = blockCount * blockSize

    override val usedSpace: Long
        get() = (blockCount - freeBlockCount) * blockSize

    override val freeSpace: Long
        get() = freeBlockCount * blockSize

    override val availableSpace: Long
        get() = availableBlockCount * blockSize

    override val updatesAccessTime: Boolean
        get() = (flags and NO_UPDATE_ACCESS_TIME) == NO_UPDATE_ACCESS_TIME

    override val isReadOnly: Boolean
        get() = (flags and READ_ONLY) == READ_ONLY

    override val updatesDirectoryAccessTime: Boolean
        get() = (flags and NO_UPDATE_DIRECTORY_ACCESS_TIME) == NO_UPDATE_DIRECTORY_ACCESS_TIME

    override val hasAccessToDevices: Boolean
        get() = (flags and NO_DEVICE_FILES) != NO_DEVICE_FILES

    override val hasAccessToExecute: Boolean
        get() = (flags and NO_EXECUTION) != NO_EXECUTION
}

val Path.fileSystemInfo: LinuxFileSystemInfo
    get() {
        checkScheme(LinuxOperationOptions.SCHEME)
        return LinuxFileOperationProvider.getFileSystemStatus(bytes)
    }
